package com.letoo.sso.dataaccess.datasource;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * 多数据源拦截器
 * 
 * @author dengjie
 *
 */
@Aspect
@Component
public class DataSourceAspect implements Ordered {

  // 每个线程变量存储我们配置的db集合
  @Value("${jdbc.db.list}")
  private String dbList;

  public String getDbList() {
    return dbList;
  }

  public void setDbList(String dbList) {
    this.dbList = dbList;
  }

  /**
   * 日志
   */
  private final Logger log = LoggerFactory.getLogger(getClass());

  @Pointcut("execution(* com.letoo.sso.core.service.*.*(..))")
  public void selectDb() {
  }

  @Before("selectDb()")
  public void before(JoinPoint point) {
    Object target = point.getTarget();
    String method = point.getSignature().getName();

    Class<?>[] classz = target.getClass().getInterfaces();

    Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();
    try {
      Method m = classz[0].getMethod(method, parameterTypes);
      if (m != null && m.isAnnotationPresent(DataSource.class)) {
        DataSource data = m.getAnnotation(DataSource.class);
        String dataSourceStr = data.value();
        // 在多个slave配置的情况下，配置slave则随机选择slave进行查询操作。
        if (dataSourceStr != null && dataSourceStr.equals("slave")) {
          String[] dbArr = dbList.split(",");
          List<String> slaves = new ArrayList<String>();
          // 只选择slave开头的DB，排除master
          for (int i = 0; i < dbArr.length; i++) {
            if (!"master".equals(dbArr[i])) {
              slaves.add(dbArr[i]);
            }
          }
          String dataSourceTarget = slaves.get((int) (Math.random() * slaves.size()));
          DynamicDataSourceHolder.putDataSource(dataSourceTarget);
        } else {
          DynamicDataSourceHolder.putDataSource(dataSourceStr);
        }
        // debug打印选择哪个数据源
        log.debug("select db is: " + DynamicDataSourceHolder.getDataSouce());
      }

    } catch (Exception e) {
      log.error("DataSourceAspect before error:", e);
    }
  }

  // order是为了保证切换数据源一定要在事务开启之前去完成。不然事务就会用上一次的数据源造成bug.0就似乎拦截器最高优先级
  @Override
  public int getOrder() {
    return 0;
  }
}
